<?php

declare(strict_types=1);

namespace DreamCat\ControllerParamGen4Laravel\Factory;

use DreamCat\Array2Class\Array2ClassConverter;
use DreamCat\Array2Class\Array2ClassInterface;
use DreamCat\ControllerParamGen\ControllerParamGeneratorInterface;
use DreamCat\ControllerParamGen\Generator\ControllerParamGenerator;
use DreamCat\ControllerParamGen\HttpBodyDecodeInterface;
use DreamCat\ControllerParamGen\ParamCreateInterface;
use Dreamcat\PropertyAnalysis\PropertyAnalysisInterface;
use Illuminate\Container\Container;
use Illuminate\Contracts\Container\BindingResolutionException;

/**
 * 控制器参数生成器的工厂
 * @author vijay
 */
class CtlParamGenFactory
{
    /**
     * @param Container $container 容器
     */
    public function __construct(private Container $container)
    {
    }

    /**
     * 创建一个控制器生成器
     * @return ControllerParamGeneratorInterface
     * @throws BindingResolutionException
     */
    public function factory(): ControllerParamGeneratorInterface
    {
        $generator = new ControllerParamGenerator($this->container, $this->createArrayConverter());
        foreach ((array)config("controllerParamGenerator.bodyDecoders") as $decoderName) {
            if (!$this->container->bound($decoderName)) {
                continue;
            }
            $decoder = $this->container->make($decoderName);
            if ($decoder instanceof HttpBodyDecodeInterface) {
                $generator->addHttpBodyDecoder($decoder);
            }
        }
        foreach ((array)config("controllerParamGenerator.specParams") as $type => $specParamName) {
            if (!$this->container->bound($specParamName)) {
                continue;
            }
            $specParam = $this->container->make($specParamName);
            if ($specParam instanceof ParamCreateInterface) {
                $generator->addSpecParam($type, $specParam);
            }
        }
        $generator->setIgnoreAnno(strval(config("controllerParamGenerator.ignoreAnno", "")));
        return $generator;
    }

    /**
     * 创建一个数组转换器
     * @return Array2ClassInterface
     * @throws BindingResolutionException
     */
    private function createArrayConverter(): Array2ClassInterface
    {
        $config = config("controllerParamGenerator.arrayConverter", []);
        $arrayConverter = new Array2ClassConverter();
        if ($config["createNewProperty"] ?? false) {
            $arrayConverter->setCreateNewProperty(true);
        }
        if ($config["tryWithoutConstructor"] ?? false) {
            $arrayConverter->setTryWithoutConstructor(true);
        }
        if (!isset($config["tryCallSetter"]) || !$config["tryCallSetter"]) {
            $arrayConverter->setTryCallSetter(false);
        }
        if (!isset($config["tryConstructWithParam"]) || !$config["tryConstructWithParam"]) {
            $arrayConverter->setTryConstructWithParam(false);
        }
        if (isset($config["propertyAnalysis"]) && $this->container->bound($config["propertyAnalysis"])) {
            $propertyAnalysis = $this->container->make($config["propertyAnalysis"]);
            if ($propertyAnalysis instanceof PropertyAnalysisInterface) {
                $arrayConverter->setPropertyAnalysis($propertyAnalysis);
            }
        }
        $o = PropertyNameTransFactory::createByMode(intval(config("controllerParamGenerator.jsonCoder.transMode", 0)));
        if ($o) {
            $arrayConverter->setPropertyNameTrans($o);
        }
        return $arrayConverter;
    }
}

# end of file
